查看原文
其他

程序员应如何理解系统调用:下篇

码农的荒岛求生 码农的荒岛求生 2020-12-18


在第一章回顾了一些重要主题:CPU内存程序进程后,第二章将正式开始操作系统系列主题,本章主要来讨论操作系统是如何来对进程进行控制的,以下为本篇目录。


API与系统调用

系统调用的过程

系统调用类型

系统调用带来的好处

    释放程序员生产力

    提高系统稳定性

    多任务以及虚拟内存




承接上文《程序员应如何理解系统调用:上篇

系统调用类型

由于一个系统的功能都是通过系统调用对外提供的,因此应用程序能够实现的最强大的功能不会超过系统调用提供给应用程序的能力。

根据类型系统调用大体可以划分为以下几类:进程控制:一个运行中的进程可以创建另外一个进程去完成某项工作,这样当前进程就有机会去处理自己感兴趣的事情,这类系统调用在Linux中是fork(),在Windows下CreateProcess()。当我们创建新的进程后,可能需要等待其运行完成,这时我们需要的系统调用是Linux下的wait()或者Windows下的WaitForSingleObject()。至于操作系统如何来管理进程将是后续章节中的重要内容。

文件管理:我们通常需要创建文件create()来持久化的保存信息,文件创建完毕后,通常在使用前我们要首先打开文件open(),然后才能进行读写read()、write()。文件使用完毕后,通常需要关闭文件close()。关于文件的这些操作都是通过系统调用来完成的。

设备管理:我们的程序在运行过程中需要使用很多系统资源才能完成任务,比如请求分配内存、访问磁盘、通过网卡收发网络数据等等,如果这些资源当前是可用的,那么我们的程序在得到这些资源后可以继续运行,否则只能暂停运行我们的程序直到这些资源可用为止。因此用户程序通常需要首先请求资源request(),使用完毕后释放资源release()。由于在Unix/Linux系统中将这些硬件资源抽象成了文件(file),因此我们可以通过对文件的读写read()、write()就能实现操作设备的目的。

信息维护:通常情况下我们需要向操作系统请求一些只有操作系统才知道的信息,比如当前的日期date(),时间time(),或者操作系统的版本信息,当前可用内存大小,剩余磁盘大小等等。另一种比较有用的信息是程序在内存中的运行数据,通过dump()进程在内存中的数据以及进程中函数的调用信息trace(),我们就可以利用调试器(比如Linux下的gdb)来调试有问题的程序。

通信:我们的进程可能需要与其它进程通信才能完成某项功能,在这里通常有两种通信模型。一种是消息传递类比如常用的网络通信,在网络通信中我们通过读写socket来实现网络数据的接收recv()和发送send(),本地的进程之间通信会通过比如Linux下的pipe()这类系统调用来完成。另一种是共享内存。在后续章节中我们会讲解这些进程间通信模型。

你会发现其实这些类型基本上涵盖了操作系统的方方面面,如果你能自己写代码实现这些系统调用,那么本质上你已经自己完成了一个操作系统。

下图是一张Windows和Linux下这几类系统调用的示例,注意这里仅仅挑选出一部分进行说明,详细的系统调需要参考具体的操作系统。



系统调用带来的好处

释放了程序员生产力

由于系统调用对程序员屏蔽了操作系统对计算机资源管理的细节,因此程序员在进行比如文件读写这样的操作时根本无需关心这些文件放在了磁盘中的什么位置上,这些文件是通过什么样的文件系统来管理的等。再者比如程序员需要进行网络通信,通过系统调用,程序员无需关心这些数据是如何被封装成TCP/IP能认识的协议数据的以及是如何通过驱动程序把数据从网卡上发送出去的。同时程序员也无需关心如何从网卡上接收数据、如何进行数据进行TCP/IP协议解析并把数据交给用户程序。程序员需要做的仅仅就是调用类似read(socket),write(socket)这样的函数就可以进行网络数据收发就可以了,这些都极大的解放了程序员生产力。


提高系统稳定性

作为用户程序和操作系统之间的一个屏障,系统调用保护了操作系统不受用户程序的干扰。通过系统调用,操作系统可以对用户请求进行权限以及合法性检查,这就阻止了用户程序随意使用系统资源。同时作为用户程序向操作系统发起请求的唯一合法途径,系统调用起到了类似海关的作用,这些无疑提高了系统稳定性。


多任务以及虚拟内存成为可能

系统调用的使用,使得操作系统可以不受干扰的控制系统资源,操作系统可以自己决定如何分配这些资源。正是因为系统调用,用户程序完全不需要知道操作系统是如何完成请求的,这种对上层的屏蔽使得多任务,虚拟内存等功能得以实现。

如果用户程序可以绕过操作系统随意控制系统资源(CPU、内存、磁盘,网卡、外设等),那么整体系统的稳定性将荡然无存。操作系统根本就没有办法实现很酷的多任务、虚拟内存等功能。试想如果我们的音乐播放程序可以一直控制着使用CPU,那么我们还怎么能一边写代码一边听音乐呢?在这种情况下只要播放音乐,那么其它程序都将不能运行,这显然不是广大程序员们希望的 :) 。


总结

在这一节中我们详细的讲述了系统调用的整个过程,作为程序员我们需要意识到是操作系统帮我们完成了对计算资源的管理,作为用户程序,我们需要做的仅仅是通过系统调用来使用操作系统赋予我们的能力。同时程序员一般不需要直接进行系统调用,而是使用更为简单易用的API(C标准库或Win32 API)就可以了。操作系统通过系统调用对用户程序屏蔽了底层细节,通过这种机制,操作系统实现了多任务、虚拟内存等重要功能,在后续的章节中我们会详细讲解这些功能是如何实现的。

计算机基础决定程序员职业生涯高度
--码农的荒岛求生

操作系统系列

基础篇
1,什么是程序

2,程序?进程?傻傻分不清

3,程序员应如何理解内存:上篇
4,程序员应如何理解内存:中篇
5,程序员应如何理解内存:下篇
6,程序员应如何理解CPU:上篇
7,程序员应如何理解CPU:下篇
系统调用篇
8,操作系统是如何看待进程的
9,系统调用是如何实现的
10,程序员应如何理解系统调用:上篇



PS:微信公众号从去年开始限制了留言功能,如果你有任何问题欢迎直接在公众号留言。

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存